home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / filesyst / xiafs / xiafspgm.8 / xiafspgm / xiafspgm-0.8.1 / mkxfs.c < prev    next >
C/C++ Source or Header  |  1993-03-11  |  16KB  |  592 lines

  1. /*
  2.  * mkxiafs.c - make a xiafs file system
  3.  */
  4. /**************************************************************************
  5.  * (C) Copyright Q. Frank Xia, 1992.  All rights reserved.                *
  6.  *                                                                        *
  7.  * Permission to use and redistribute this software is hereby granted     *
  8.  * provided that the following conditions are met:                        *
  9.  * 1. Source code redistribution must retain this statement.              *
  10.  * 2. Binary redistribution must reproduce this statement in the          *
  11.  *    documentation provided with the distribution.                       *
  12.  * 3. This software is provided by author Q. Frank Xia "as is". There     *
  13.  *    are absolutely no warranties at all. The author is not responsible  *
  14.  *    for any possible damages caused by using this software.             *
  15.  **************************************************************************/
  16.  
  17. /*
  18.  * Usage: mkxiafs [-c | -l path] [-k size] [-z size] device size
  19.  * 
  20.  * size is in KB.
  21.  *
  22.  *    -c    readablility checking.
  23.  *    -k    reserve 'size' KB for kernel image.
  24.  *      -l    getting a list of bad blocks from a file.
  25.  *      -z    'size' KB in a zone, 1 KB is default.
  26.  */
  27.  
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <unistd.h>
  31. #include <signal.h>
  32. #include <fcntl.h>
  33. #include <sys/stat.h>
  34. #include <time.h>
  35. #include <linux/fs.h>
  36. #include <linux/xia_fs.h>
  37. #include <ctype.h>
  38. #include <stdlib.h>
  39. #include <string.h>
  40. #include <getopt.h>
  41.  
  42. #if BLOCK_SIZE != 1024
  43. #error "only block size 1024 supported"
  44. #endif
  45.  
  46. #define ZONE_SIZE        (BLOCK_SIZE << zone_shift)
  47. #define BITS_PER_ZONE       (BLOCK_SIZE << (3 + zone_shift))
  48. #define BITS_PER_ZONE_BITS    (BLOCK_SIZE_BITS + 3 + zone_shift)
  49. #define ADDR_PER_ZONE       (BLOCK_SIZE >> (2 - zone_shift))
  50.  
  51. #define NR_INODES    (INODE_ZONES * _XIAFS_INODES_PER_BLOCK << zone_shift)
  52. #define INODE_ZONES    (((zones - kern_zones) >> (2 + zone_shift)) \
  53.              / _XIAFS_INODES_PER_BLOCK + 1)
  54. #define IMAP_ZONES     (NR_INODES / BITS_PER_ZONE + 1)
  55. #define ZMAP_ZONES     ((zones - kern_zones) / BITS_PER_ZONE + 1)
  56. #define FIRST_KERN_ZONE (1 + IMAP_ZONES + ZMAP_ZONES + INODE_ZONES)
  57. #define FIRST_DATA_ZONE (FIRST_KERN_ZONE + kern_zones)
  58. #define NR_DATA_ZONES    (zones - FIRST_DATA_ZONE)
  59. #define MAX_SIZE    (zone_shift == 2 ? 0xffffffff : \
  60.              (((ADDR_PER_ZONE+1)*ADDR_PER_ZONE)+8) * ZONE_SIZE)
  61.  
  62. char *pgm;            /* program name */
  63. u_char *zone_buf;        /* main buffer */
  64. u_long *indz_buf;        /* inderect zone buffer */
  65. u_long *dindz_buf;        /* double inderect zone buffer */
  66. int zones;            /* size of the file system in zones */
  67. int kern_zones=0;             /* nr of reserved zones for kernal image */
  68. int zone_shift=0;        /* ZONE_SIZE = BLOCK_SIZE << zone_shfit */
  69. int bad_zones=0;        /* # of bad zones */
  70. int *bad_zlist=(int *) 0;
  71. int dev;
  72.  
  73. /*-----------------------------------------------------------------------
  74.  * error process rutines
  75.  */
  76. void usage()
  77. {
  78.   fprintf(stderr, 
  79.       "usage: mkxiafs [-c | -l path] [-k size] [-z size] device size\n");
  80.   exit(1);
  81. }
  82.  
  83. void die(char *cp)
  84. {
  85.   fprintf(stderr, "%s: %s\n", pgm, cp);
  86.   exit(1);
  87. }
  88.  
  89. /*------------------------------------------------------------------------
  90.  * error free read/write rutines
  91.  */
  92. void rd_zone(int zone_nr, void *buffer)
  93. {
  94.   if (lseek(dev, zone_nr * ZONE_SIZE, SEEK_SET) < 0)
  95.     die("seek device failed");
  96.   if (read(dev, buffer, ZONE_SIZE) < 0)
  97.     die("read device failed");
  98. }
  99.  
  100. void wt_zone(int zone_nr, void *buffer)
  101. {
  102.   if (lseek(dev, zone_nr * ZONE_SIZE, SEEK_SET) < 0)
  103.     die("seek device failed");
  104.   if (write(dev, buffer, ZONE_SIZE) < 0)
  105.     die("write device failed");
  106. }
  107.  
  108. /*----------------------------------------------------------------------
  109.  * bad block check / read bad block from a file
  110.  */
  111. static int zones_done=0;
  112.  
  113. void save_bad_num(int num)
  114. {
  115.   static int bad_zlist_size=0;
  116.   
  117.   if (bad_zones >= bad_zlist_size) {
  118.     bad_zlist_size += BLOCK_SIZE;
  119.     if (!(bad_zlist=realloc(bad_zlist, bad_zlist_size >> 2)))
  120.       die("allocate memory failed");
  121.   }
  122.  
  123.   bad_zlist[bad_zones++]=num;
  124. }
  125.  
  126. void alarm_intr() 
  127. {
  128.   if (zones_done >= zones)
  129.     return;
  130.   signal(SIGALRM, alarm_intr);        /* set for next alarm */
  131.   alarm(2);                /* alarm in 2 seconds */
  132.   printf("%d... ", zones_done);        /* report how many blocks checked */
  133.   fflush(stdout);
  134. }
  135.  
  136. void do_bad_ck()
  137. {
  138.   FILE *bf;
  139.   int i;
  140.  
  141.   signal(SIGALRM, alarm_intr);        /* set alarm */
  142.   alarm(2);
  143.  
  144.   if (lseek(dev, 0, SEEK_SET) < 0)    /* ready to start */
  145.     die("seek device failed");
  146.  
  147.   while (zones_done++ < zones) {    /* try twice */
  148.     if (read(dev, zone_buf, BLOCK_SIZE) < 0 ) {
  149.       if (lseek(dev, (zones_done-1) * BLOCK_SIZE, SEEK_SET) < 0)
  150.     die("seek device failed");
  151.       if (read(dev, zone_buf, BLOCK_SIZE) < 0) {      
  152.     if (lseek(dev, zones_done * BLOCK_SIZE, SEEK_SET) < 0)
  153.       die("seek device fail");
  154.     save_bad_num(zones_done-1);    /* record bad blk, 0 based */
  155.       }
  156.     }
  157.   }
  158.   printf("\n");
  159.   bf=fopen("badblocks.log", "w");
  160.   if (!bf) {
  161.     fprintf(stderr, "open file \'badblocks.log\' failed\n");
  162.     return;
  163.   }
  164.   for (i=0; i < bad_zones; i++)
  165.     fprintf(bf, "%d\n", bad_zlist[i]);
  166.   fclose(bf);
  167. }
  168.  
  169. void rd_bad_num(char *bad_nr_file)
  170. {
  171.   int tmp, notdone=1;            /* read bad block # from a file */
  172.   char *cp;                /* each line contains a single # */
  173.   FILE *fp;
  174.  
  175.   if (!(fp=fopen(bad_nr_file, "r"))) 
  176.     die("open bad block number file failed");
  177.  
  178.   while ( notdone ) {
  179.     if (!fgets(zone_buf, 128, fp)) {
  180.       if (!feof(fp))
  181.         die("read bad block number file fail");
  182.       notdone=0;    
  183.     } else {
  184.       tmp=strtol(zone_buf, &cp, 0);
  185.       if ( !isspace(*cp) && *cp)
  186.         die("invalid bad block number file");
  187.       save_bad_num(tmp);
  188.     }
  189.   }
  190.  
  191.   for (tmp=1; tmp < bad_zones; tmp++) {        /* recycle temp */
  192.     if (bad_zlist[tmp-1] >= bad_zlist[tmp])
  193.       die("invalid bad block number file");
  194.   }
  195.   if (bad_zlist[bad_zones] >= zones) 
  196.     die("bad block number > volume");
  197. }
  198.  
  199. void fatal_bad_ck()
  200. {
  201.   int i;
  202.  
  203.   if (!bad_zones || (bad_zlist[0] >> zone_shift) > FIRST_DATA_ZONE) 
  204.     return;
  205.   fprintf(stderr, "bad zone%s:", (bad_zones==1) ? "": "s");
  206.   for (i=0; i < 20 && i < bad_zones; i++)
  207.     fprintf(stderr, "  %d", bad_zlist[i]);
  208.   if (i != bad_zones)
  209.     fprintf(stderr, " ...");
  210.   fprintf(stderr, "\nfirst data block:  %d\n",(FIRST_DATA_ZONE+1)<<zone_shift);
  211.   die("bad blocks in critical area");
  212. }
  213.  
  214. void bad_blk_to_zone()
  215. {
  216.   int i, *ip1, *ip2, *endp;
  217.   
  218.   for (i=0; i < bad_zones; i++)
  219.     bad_zlist[i] >>= zone_shift;
  220.   ip1=bad_zlist;
  221.   ip2=bad_zlist;
  222.   endp=bad_zlist+bad_zones;
  223.   while (ip2 < endp) {
  224.     *ip1=*ip2++;
  225.     while (ip2 < endp && *ip1==*ip2) ip2++;
  226.     ip1++;
  227.   }
  228.   bad_zones=ip1-bad_zlist;
  229. }
  230.  
  231. /*----------------------------------------------------------------------
  232.  * make super block
  233.  */
  234. void do_sup_zone()
  235. {
  236.   struct xiafs_super_block * sp;
  237.  
  238.   memset(zone_buf, 0, ZONE_SIZE);
  239.   sp=(struct xiafs_super_block *)zone_buf;
  240.   sp->s_zone_size=ZONE_SIZE;
  241.   sp->s_nzones=zones;
  242.   sp->s_ninodes=NR_INODES;
  243.   sp->s_ndatazones=NR_DATA_ZONES;
  244.   sp->s_imap_zones=IMAP_ZONES;
  245.   sp->s_zmap_zones=ZMAP_ZONES;
  246.   sp->s_firstdatazone=FIRST_DATA_ZONE;
  247.   sp->s_zone_shift=zone_shift;
  248.   sp->s_max_size=MAX_SIZE;
  249.   sp->s_firstkernzone=kern_zones ? FIRST_KERN_ZONE : 0;
  250.   sp->s_magic=_XIAFS_SUPER_MAGIC;
  251.  
  252.   wt_zone(0, zone_buf);
  253. }
  254.  
  255. /*-------------------------------------------------------------------------
  256.  * make imap and zmap
  257.  */
  258. void do_map_zones(int start_zone, int nr_zones, int nr_bits, int first_byte)
  259. {
  260.   int i;
  261.   int bits, bytes;
  262.  
  263.   bits=nr_bits & 7;
  264.   bytes=nr_bits >> 3;
  265.  
  266.   for (i=0; i < nr_zones; i++) {
  267.     if (!bytes && !bits) {
  268.       memset(zone_buf, 0xff, ZONE_SIZE);
  269.     } else if (bytes < ZONE_SIZE) {
  270.       memset(zone_buf, 0, bytes);
  271.       zone_buf[bytes]=255 << bits;
  272.       memset(zone_buf+bytes+1, 0xff, ZONE_SIZE-bytes-1);
  273.       bytes=0;
  274.       bits=0;
  275.     } else {
  276.       memset(zone_buf, 0, ZONE_SIZE);
  277.       bytes-=ZONE_SIZE;
  278.     }
  279.     if (!i)
  280.       zone_buf[0]=first_byte;
  281.     wt_zone(start_zone+i, zone_buf);
  282.   }
  283. }
  284.  
  285. #define do_imap()   do_map_zones(1, IMAP_ZONES, NR_INODES+1, 7)
  286.  
  287. #define do_zmap()   do_map_zones(1+IMAP_ZONES, ZMAP_ZONES, NR_DATA_ZONES+1, 3)
  288.  
  289. /*------------------------------------------------------------------------
  290.  * make a file for bad blocks. All bad blocks link to ino 2.
  291.  */
  292. #define set_bit(bit_nr)        (zone_buf[(bit_nr) >> 3] |= 1 << ((bit_nr) & 7))
  293.  
  294. #define z_to_bnr(zone_nr)   ((zone_nr)-FIRST_DATA_ZONE+1)
  295. #define bnr_to_z(bit_nr)    ((bit_nr)-1+FIRST_DATA_ZONE)
  296.     
  297. void do_bad_bits()
  298. {
  299.   int i, znr, cur_znr=-1;
  300.  
  301.   for (i=0; i < bad_zones; i++) {
  302.     if ((znr = z_to_bnr(bad_zlist[i]) >> BITS_PER_ZONE_BITS) != cur_znr) {
  303.       if (cur_znr >= 0) 
  304.     wt_zone(1+IMAP_ZONES+cur_znr, zone_buf);
  305.       rd_zone(1+IMAP_ZONES+znr, zone_buf);
  306.       cur_znr=znr;
  307.     }
  308.     set_bit(z_to_bnr(bad_zlist[i]) & (BITS_PER_ZONE -1));
  309.   }
  310.   if (cur_znr >= 0)
  311.     wt_zone(1+IMAP_ZONES+cur_znr, zone_buf);
  312. }
  313.  
  314. static int last_used=1;
  315. static int next_bad_ind=0;
  316.  
  317. u_long get_free_zone()
  318. {
  319.   int i;
  320.   u_long tmp;
  321.  
  322.   for (i=last_used+1; i < NR_DATA_ZONES; i++) {
  323.     tmp=bnr_to_z(i);                
  324.     if (tmp != bad_zlist[next_bad_ind]) {        
  325.       last_used=i;                /* good zone find */
  326.       rd_zone(1+IMAP_ZONES+(i>>BITS_PER_ZONE_BITS), zone_buf);
  327.       set_bit(i & (BITS_PER_ZONE-1));        /* read in zmap, set z-bit */
  328.       wt_zone(1+IMAP_ZONES+(i>>BITS_PER_ZONE_BITS), zone_buf); 
  329.       return tmp;                /* write back zmap */
  330.     }
  331.     next_bad_ind++;            /* bad zone, skip this zone */
  332.   }
  333.   die("too many bad zones");        /* no good zone */
  334.   return 0;
  335. }
  336.  
  337. void mk_bad_file(struct xiafs_inode *inode_pt)
  338. {
  339.   int i, di, bad_zs, good_z=0;
  340.  
  341.   bad_zs=bad_zones;                             /* keep bad_zones */
  342.   if (bad_zs <= 8) {                /* only direct zones */
  343.     for (i=0; i < bad_zs; i++)
  344.       inode_pt->i_zone[i]=bad_zlist[i];        /* fill and done */
  345.   } else {
  346.     for (i=0; i < 8; i++)            /* have indirect zones */  
  347.       inode_pt->i_zone[i]=bad_zlist[i];        /* fill direct zones */
  348.     inode_pt->i_ind_zone=get_free_zone();    /* get indirect ptr zone */
  349.     good_z++;
  350.     if (bad_zs > 8 + ADDR_PER_ZONE) {        /* have dindirect zones */
  351.       inode_pt->i_dind_zone=get_free_zone();    /* get dindirect ptr zone */
  352.       good_z++;
  353.     }
  354.   }
  355.  
  356.   bad_zs -= 8;                    /* bad zone left */
  357.   if (bad_zs > 0) {                    /* have indirect zones */
  358.     if (bad_zs > ADDR_PER_ZONE) {        
  359.       for (i=0; i < ADDR_PER_ZONE; i++)        /* fill indirect ptr zone */
  360.     indz_buf[i]=bad_zlist[i+8];    
  361.     } else {
  362.       for (i=0; i < bad_zs; i++)
  363.     indz_buf[i]=bad_zlist[i+8];
  364.       for (; i < ADDR_PER_ZONE; i++)
  365.     indz_buf[i]=0;
  366.     }
  367.     wt_zone(inode_pt->i_ind_zone, indz_buf);    /* save it */
  368.     bad_zs -= ADDR_PER_ZONE;            /* bad zone left */
  369.   }
  370.   if (bad_zs > 0) {                /* have dindirect zones */
  371.     for (di=0; di < ADDR_PER_ZONE; di++) {    /* do 2nd */
  372.       if (bad_zs > 0) {
  373.     dindz_buf[di]=get_free_zone();        /* get 2nd level ptr zone */
  374.     good_z++;
  375.     if (bad_zs > ADDR_PER_ZONE) {
  376.       for (i=0; i < ADDR_PER_ZONE; i++)    /* fill 2nd level ptr zone */
  377.         indz_buf[i]=bad_zlist[8+(1+di)*ADDR_PER_ZONE+i];
  378.     } else {
  379.       for (i=0; i < bad_zs; i++)
  380.         indz_buf[i]=bad_zlist[8+(1+di)*ADDR_PER_ZONE+i];
  381.       for (; i < ADDR_PER_ZONE; i++)
  382.         indz_buf[i]=0;
  383.     }
  384.     wt_zone(dindz_buf[di], indz_buf);    /* write back */
  385.     bad_zs -= ADDR_PER_ZONE;        /* bad zones left */
  386.       } else
  387.     dindz_buf[di]=0;            /* no bad zones any more */
  388.       wt_zone(inode_pt->i_dind_zone, dindz_buf);
  389.     }
  390.   }
  391.   good_z = (good_z + bad_zones) << (zone_shift + 1);
  392.   inode_pt->i_zone[0] |= (good_z << 24) & 0xff000000;
  393.   inode_pt->i_zone[1] |= (good_z << 16) & 0xff000000;
  394.   inode_pt->i_zone[2] |= (good_z <<  8) & 0xff000000;
  395. }
  396.  
  397. /*------------------------------------------------------------------------
  398.  * make inodes
  399.  */
  400. void do_inode_zones()
  401. {
  402.   int i;
  403.   char *cp;
  404.   struct xiafs_inode ti, *ip;
  405.  
  406.   memset(&ti, 0, sizeof(struct xiafs_inode));
  407.   ti.i_mode=S_IFREG;
  408.   ti.i_uid=getuid();
  409.   ti.i_gid=getgid();
  410.   ti.i_nlinks=1;
  411.   ti.i_size=bad_zones * ZONE_SIZE;
  412.   ti.i_mtime=ti.i_atime=ti.i_atime=time(NULL);
  413.   mk_bad_file(&ti);
  414.  
  415.   if (!(cp=getenv("umark")))
  416.     i=0777;
  417.   else
  418.     i= (~atoi(cp)) & 0777;
  419.   memset(zone_buf, 0, ZONE_SIZE);
  420.   ip=(struct xiafs_inode *)zone_buf;
  421.   ip->i_mode=S_IFDIR | i;
  422.   ip->i_uid=ti.i_uid;
  423.   ip->i_gid=ti.i_gid;
  424.   ip->i_nlinks=2;
  425.   ip->i_size=ZONE_SIZE;
  426.   ip->i_mtime=ip->i_ctime=ip->i_atime=ti.i_mtime;
  427.   ip->i_zone[0]=FIRST_DATA_ZONE | (2 << 24);
  428.   ip++;
  429.   *ip=ti;
  430.  
  431.   wt_zone(1+IMAP_ZONES+ZMAP_ZONES, zone_buf);
  432.   memset(zone_buf, 0, ZONE_SIZE);
  433.   for (i=1; i < INODE_ZONES; i++)
  434.     wt_zone(1+IMAP_ZONES+ZMAP_ZONES+i, zone_buf);
  435. }
  436.  
  437. /*-----------------------------------------------------------------------
  438.  * fill kernel image zones with 0
  439.  */
  440. void do_kern_image()
  441. {
  442.   int i;
  443.   
  444.   memset(zone_buf, 0, ZONE_SIZE);
  445.   for (i=FIRST_KERN_ZONE; i < FIRST_DATA_ZONE; i++)
  446.     wt_zone(i, zone_buf);
  447. }
  448.  
  449. /*-----------------------------------------------------------------------
  450.  *
  451.  */
  452. void do_root_dir()
  453. {
  454.   struct xiafs_direct * dir_entry_pt;
  455.  
  456.   memset(zone_buf, 0, ZONE_SIZE);
  457.   dir_entry_pt=(struct xiafs_direct *)zone_buf;
  458.   dir_entry_pt->d_ino=1;
  459.   dir_entry_pt->d_rec_len=12;
  460.   dir_entry_pt->d_name_len=1;
  461.   dir_entry_pt->d_name[0]='.';
  462.   dir_entry_pt=(struct xiafs_direct *)((u_char *)dir_entry_pt+12);
  463.   dir_entry_pt->d_ino=1;
  464.   dir_entry_pt->d_rec_len=ZONE_SIZE-12;
  465.   dir_entry_pt->d_name_len=2;
  466.   dir_entry_pt->d_name[0]='.';
  467.   dir_entry_pt->d_name[1]='.';
  468.  
  469.   wt_zone(FIRST_DATA_ZONE, zone_buf); 
  470. }
  471.  
  472. /*------------------------------------------------------------------------
  473.  * test physical size
  474.  */
  475. void last_zone_test()
  476. {
  477.   if (FIRST_DATA_ZONE >= zones)
  478.     die("device too small");
  479.   *(u_long *)(zone_buf+ZONE_SIZE-4)=_XIAFS_SUPER_MAGIC;
  480.   wt_zone(zones-1, zone_buf);
  481.   sync();
  482.   memset(zone_buf, 0, ZONE_SIZE);
  483.   rd_zone(zones-1, zone_buf);
  484.   if (*(u_long *)(zone_buf+ZONE_SIZE-4)!=_XIAFS_SUPER_MAGIC) {
  485.     sprintf(zone_buf, "device < %d zones", zones);
  486.     die(zone_buf);
  487.   }
  488. }
  489.  
  490. /*---------------------------------------------------------------------
  491.  * report
  492.  */
  493. void report()
  494. {
  495.   printf("     zone size: %d KB\n", 1<<zone_shift);
  496.   printf("    total size: %d zones\n", zones);
  497.   printf("        inodes: %d\n", NR_INODES);
  498.   printf("    data zones: %d\n", NR_DATA_ZONES);
  499.   printf("kernel reserve: %d zone%s\n", kern_zones, kern_zones < 2 ? "":"s");
  500.   printf(" max file size: %d MB\n", MAX_SIZE >> 20);
  501.   if (bad_zlist)
  502.     printf("     bad zones: %d ( %d%% )\n", bad_zones, 
  503.        (bad_zones*100+NR_DATA_ZONES/2)/NR_DATA_ZONES);
  504. }
  505.  
  506. /*---------------------------------------------------------------------
  507.  * main rutine
  508.  */
  509. void main(int argc, char * argv[])
  510. {
  511.   int bad_ck=0;
  512.   char *bad_nr_file=(char *) 0;
  513.   char *dev_name;
  514.   char *endp;
  515.   int opt;
  516.  
  517.   extern int optind;
  518.   extern char *optarg;
  519.  
  520.   pgm=argv[0];
  521.   if (getuid())
  522.     die("this program can only be run by root");
  523.   while ((opt=getopt(argc, argv, "ck:l:z:")) != EOF) {
  524.     switch (opt) {
  525.     case 'c':
  526.       bad_ck=1;
  527.       break;
  528.     case 'k':
  529.       kern_zones=strtol(optarg, &endp, 0);
  530.       if (!isspace(*endp) && *endp)
  531.     usage();
  532.       if (kern_zones < 0)
  533.           usage();
  534.       break;
  535.     case 'l':
  536.       bad_nr_file=optarg;
  537.       break;
  538.     case 'z':
  539.       zone_shift=strtol(optarg, &endp, 0);
  540.       if (!isspace(*endp) && *endp)
  541.     usage();
  542.       if (zone_shift != 1 && zone_shift != 2 && zone_shift != 4)
  543.     usage();
  544.       zone_shift >>= 1;
  545.       break;
  546.     default:
  547.       usage();
  548.     }
  549.   }
  550.   if (bad_ck && bad_nr_file)
  551.     usage();
  552.   if (argc != optind+2)
  553.     usage();
  554.   dev_name=argv[optind];
  555.   zones=strtol(argv[optind+1], &endp, 0) & ~((1 << zone_shift) - 1);
  556.   if ( !isspace(*endp) && *endp)
  557.     usage();
  558.   if (zones < 0 || zones > 0x400000)
  559.     die("invalid volume size");
  560.   if ((dev=open(dev_name, O_RDWR)) < 0)
  561.     die("open device failed");
  562.   if (!(zone_buf=(u_char *)malloc(3 * ZONE_SIZE)))
  563.     die("allocate memory failed");
  564.   indz_buf=(u_long *)(zone_buf+ZONE_SIZE);
  565.   dindz_buf=(u_long *)(zone_buf+ZONE_SIZE*2);
  566.  
  567.   zones >>= zone_shift;
  568.   kern_zones = (kern_zones + (1 << zone_shift) - 1 )>> zone_shift;
  569.  
  570.   last_zone_test();
  571.  
  572.   if (bad_ck)
  573.     do_bad_ck();
  574.   if (bad_nr_file)
  575.     rd_bad_num(bad_nr_file);
  576.  
  577.   fatal_bad_ck();
  578.   bad_blk_to_zone();
  579.   
  580.   do_sup_zone();
  581.   do_imap();
  582.   do_zmap();
  583.   do_bad_bits();
  584.   do_inode_zones();
  585.   do_kern_image();
  586.   do_root_dir();
  587.   report();
  588.  
  589.   exit(0);
  590. }
  591.  
  592.